﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Data.Linq;
using System.Xml.Linq;
using System.Net;
using System.IO;

using ICSharpCode.SharpZipLib.Zip;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
using System.ComponentModel;
using System.Runtime.Remoting.Messaging;


namespace MyMoviesBrowserLibrary
{
    public enum SettingsEnum
    {
        ChoosenLanuage
    }

    public delegate void UpdateEvent(string updateText);
    public delegate void AddFileToSeriesEvent(Episode episode);    
    public delegate void AddFilesToSeriesEvent(List<Episode> episodes);
    public delegate void AddSeriesEvent(Series series);
    public delegate void UpdateEpisodeFilesEvent(List<Episode> episodes);

    public class TVManagerBusinessLayer
    {
        public event UpdateEvent DataUpdated;

        private const string SeriesSearchUrl = "http://www.thetvdb.com/api/GetSeries.php?seriesname={0}&language={1}";
        private const string SeriesUrl = "http://www.thetvdb.com/api/{0}/series/{1}/all/{2}.zip";
        public const string GraphicsUrl = "http://images.thetvdb.com/banners/";

        public const string APIKEY = "4C6A85250D970621";
        public static MyMoviesBrowserDataContext Ctx { get; set; }
        public string ChoosenLanguage
        {
            get
            {
                Setting setting = Ctx.Settings.SingleOrDefault(s => s.SettingName == SettingsEnum.ChoosenLanuage.ToString());
                if (setting == null)
                    return string.Empty;
                else
                    return setting.SettingValue;
            }
            set
            {
                Setting setting = Ctx.Settings.SingleOrDefault(s => s.SettingName == SettingsEnum.ChoosenLanuage.ToString());
                if (setting == null)
                {
                    setting = new Setting() { SettingName = SettingsEnum.ChoosenLanuage.ToString(), SettingValue = value };
                    Ctx.Settings.InsertOnSubmit(setting);
                }
                else
                    setting.SettingValue = value;
                Ctx.SubmitChanges();
            }
        }

        static TVManagerBusinessLayer()
        {
            Ctx = MyMoviesBrowserBusiness.GetNewMyMoviesBrowserDataContext();
        }

        public MyMoviesBrowserDataContext GetContext()
        {
            return MyMoviesBrowserBusiness.GetNewMyMoviesBrowserDataContext();
        }

        public List<Language> GetLanguages()
        {
            if (Ctx.Languages.Count() == 0)
            {
                XDocument doc = XDocument.Load(string.Format("http://www.thetvdb.com/api/{0}/languages.xml", APIKEY));

                var q = from l in doc.Descendants("Language")
                        select new Language() { Name = l.Element("name").Value, Abbreviation = l.Element("abbreviation").Value };

                Ctx.Languages.InsertAllOnSubmit(q);
                Ctx.SubmitChanges();
            }

            return Ctx.Languages.OrderBy(l => l.Name).ToList();
        }

        public List<Series> GetSeries()
        {
            MyMoviesBrowserDataContext ctx = GetContext();
            //DataLoadOptions options = new DataLoadOptions();
            //options.LoadWith<Series>(s => s.Episodes);
            //options.LoadWith<Series>(s => s.Seasons);
            //options.LoadWith<Series>(s => s.Series_Genres);
            //options.LoadWith<Series>(s => s.Series_Persons);
            //options.LoadWith<Series>(s => s.TVContentRating);
            //options.LoadWith<Series>(s => s.TVStatus);
            //ctx.LoadOptions = options;

            return ctx.Series.OrderBy(s => s.OrderName).ToList();
        }

        public Series GetSeries(int seriesId)
        {
            MyMoviesBrowserDataContext ctx = GetContext();
            DataLoadOptions options = new DataLoadOptions();
            options.LoadWith<Series>(s => s.Episodes);
            options.LoadWith<Series>(s => s.Seasons);
            options.LoadWith<Series>(s => s.Series_Genres);
            options.LoadWith<Series>(s => s.Series_Persons);
            options.LoadWith<Series>(s => s.TVContentRating);
            options.LoadWith<Series>(s => s.TVStatus);
            ctx.LoadOptions = options;

            return ctx.Series.SingleOrDefault(s => s.SeriesId == seriesId);
        }

        //public Series UpdateSeries(Series series)
        //{
        //    MyMoviesBrowserDataContext ctx = GetContext();
        //    ctx.Series.Attach(series,true);

        //    try
        //    {
        //        ctx.SubmitChanges();
        //    }
        //    catch (ChangeConflictException)
        //    {
        //        ctx.ChangeConflicts.ResolveAll(RefreshMode.KeepCurrentValues);
        //        ctx.SubmitChanges();
        //    }
        //    return series;
        //}

        public List<Series> SearchForSeries(string seriesName)
        {
            XDocument doc = XDocument.Load(string.Format(SeriesSearchUrl, seriesName, ChoosenLanguage));

            List<Series> seriesList = new List<Series>();

            DateTime tempDate;
            foreach (XElement xseries in doc.Descendants("Series"))
            {
                Series series = new Series()
                        {
                            SeriesId = int.Parse(xseries.Element("seriesid").Value),
                            SeriesName = xseries.Element("SeriesName").Value,
                            Banner = xseries.Element("banner") != null ? xseries.Element("banner").Value : "",
                            Overview = xseries.Element("Overview") != null ? xseries.Element("Overview").Value : ""
                        };
                if (xseries.Element("FirstAired") != null && DateTime.TryParse(xseries.Element("FirstAired").Value, out tempDate))
                    series.FirstAired = tempDate;

                seriesList.Add(series);
            }

            return seriesList;
        }

        private delegate Series AddSeriesDelegate(int seriesId, string folderLocation);
        public Series AddSeries(int seriesId, string folderLocation)
        {
            MyMoviesBrowserDataContext ctx = GetContext();
            //var group = ctx.Persons.GroupBy(p => p.PersonName).Where(g => g.Count() > 1).Select(g=>g.Key);

            //foreach (string name in group)
            //{
            //    Person person = ctx.Persons.Where(p => p.PersonName == name).ToList().LastOrDefault();
            //    if (person != null)
            //    {

            //        ctx.Series_Persons.DeleteAllOnSubmit(person.Series_Persons);
            //        ctx.Episode_Persons.DeleteAllOnSubmit(person.Episode_Persons);
            //        ctx.Persons.DeleteOnSubmit(person);
            //    }
            //}
            //ctx.SubmitChanges();

            Series series = null;

            if (DataUpdated != null)
                DataUpdated("Downloading Series Data");
            try
            {
                string seriesXml = "", bannersXml = "", actorsXml = "";


                WebClient client = new WebClient();
                string downloadUrl = string.Format(SeriesUrl, APIKEY, seriesId, ChoosenLanguage);
                byte[] zipData = client.DownloadData(downloadUrl);
                using (MemoryStream memStream = new MemoryStream(zipData))
                {
                    using (ZipInputStream s = new ZipInputStream(memStream))
                    {
                        ZipEntry zipEntry;

                        while ((zipEntry = s.GetNextEntry()) != null)
                        {
                            using (MemoryStream tempStream = new MemoryStream())
                            {

                                if (!string.IsNullOrEmpty(zipEntry.Name))
                                {
                                    int size = 2048;
                                    byte[] data = new byte[2048];
                                    while ((size = s.Read(data, 0, data.Length)) > 0)
                                        tempStream.Write(data, 0, size);

                                    switch (zipEntry.Name)
                                    {
                                        case "actors.xml":
                                            actorsXml = System.Text.Encoding.UTF8.GetString(tempStream.ToArray());
                                            break;
                                        case "banners.xml":
                                            bannersXml = System.Text.Encoding.UTF8.GetString(tempStream.ToArray());
                                            break;
                                        default:
                                            seriesXml = System.Text.Encoding.UTF8.GetString(tempStream.ToArray());
                                            break;
                                    }
                                }
                            }
                        }

                    }
                }

                if (!string.IsNullOrEmpty(seriesXml))
                {
                    ParseSeriesXml(ref series, ref ctx, seriesXml, folderLocation);
                    if (series != null)
                        ParseEpisodesXml(ref series, ref ctx, seriesXml);

                    if (series != null && !string.IsNullOrEmpty(bannersXml))
                        ParseBannersXml(ref series, ref ctx, bannersXml);

                    if (series != null && !string.IsNullOrEmpty(actorsXml))
                        ParseActorsXml(ref series, ref ctx, actorsXml);
                }



            }
            catch (Exception ex) { }

            return series;
        }
        public void AddSeriesAsync(int seriesId, string folderLocation)
        {
            AddSeriesDelegate worker = new AddSeriesDelegate(AddSeries);
            AsyncCallback completedCallback = new AsyncCallback(AddSeriesCallback);

            AsyncOperation async = AsyncOperationManager.CreateOperation(null);
            worker.BeginInvoke(seriesId, folderLocation, completedCallback, async);
        }
        private void AddSeriesCallback(IAsyncResult ar)
        {
            // get the original worker delegate and the AsyncOperation instance
            AddSeriesDelegate worker =
              (AddSeriesDelegate)((AsyncResult)ar).AsyncDelegate;
            AsyncOperation async = (AsyncOperation)ar.AsyncState;

            // finish the asynchronous operation
            Series series = worker.EndInvoke(ar);

            // raise the completed event
            async.PostOperationCompleted(
              delegate(object e)
              { OnAddSeriesCompleted((Series)e); },
              series);
        }

        public event AddSeriesEvent AddSeriesCompleted;
        protected virtual void OnAddSeriesCompleted(Series e)
        {
            if (AddSeriesCompleted != null)
                AddSeriesCompleted(e);
        }

        private void ParseSeriesXml(ref Series series, ref MyMoviesBrowserDataContext ctx, string xml, string folderLocation)
        {
            if (DataUpdated != null)
                DataUpdated("Parsing Series Data");
            try
            {
                XDocument doc = XDocument.Parse(xml);
                XElement xseries = doc.Descendants("Series").FirstOrDefault();
                if (xseries == null)
                    return;

                int seriesId = int.Parse(xseries.Element("id").Value);

                series = ctx.Series.SingleOrDefault(s => s.SeriesId == seriesId);
                if (series == null)
                {
                    series = new Series() { SeriesId = seriesId };
                    ctx.Series.InsertOnSubmit(series);
                }

                series.FolderLocation = folderLocation;

                string temp = "";
                DateTime tempDate;
                decimal tempDecimal;
                int tempInt;

                series.AirsDayOfWeek = xseries.Element("Airs_DayOfWeek") != null ? xseries.Element("Airs_DayOfWeek").Value : "";
                series.AirsTime = xseries.Element("Airs_Time") != null ? xseries.Element("Airs_Time").Value : "";
                if (xseries.Element("FirstAired") != null)
                {
                    if (DateTime.TryParse(xseries.Element("FirstAired").Value, out tempDate))
                        series.FirstAired = tempDate;
                    else
                        series.FirstAired = null;
                }
                series.IMDB_ID = xseries.Element("IMDB_ID") != null ? xseries.Element("IMDB_ID").Value : "";
                series.Overview = xseries.Element("Overview") != null ? xseries.Element("Overview").Value : "";
                if (xseries.Element("Rating") != null)
                {
                    if (decimal.TryParse(xseries.Element("Rating").Value, out tempDecimal))
                        series.Rating = tempDecimal;
                    else
                        series.Rating = null;
                }
                if (xseries.Element("Runtime") != null)
                {
                    if (int.TryParse(xseries.Element("Runtime").Value, out tempInt))
                        series.Runtime = tempInt;
                    else
                        series.Runtime = null;
                }
                if (xseries.Element("SeriesID") != null)
                {
                    if (int.TryParse(xseries.Element("SeriesID").Value, out tempInt))
                        series.TVSeriesId = tempInt;
                    else
                        series.TVSeriesId = null;
                }
                series.SeriesName = series.OrderName = xseries.Element("SeriesName") != null ? xseries.Element("SeriesName").Value.Trim() : "";
                if (series.OrderName.ToLower().StartsWith("the"))
                    series.OrderName = series.OrderName.Substring(4) + ", The";

                if (xseries.Element("lastupdated") != null)
                {
                    if (decimal.TryParse(xseries.Element("lastupdated").Value, out tempDecimal))
                        series.LastUpdated = tempDecimal;
                    else
                        series.LastUpdated = null;
                }

                bool downloadBanner, downloadFanart, downloadPoster;
                downloadBanner = downloadFanart = downloadPoster = false;
                if (string.IsNullOrEmpty(series.Banner))
                {
                    series.Banner = xseries.Element("banner") != null ? xseries.Element("banner").Value : "";
                    downloadBanner = true;
                }
                if (string.IsNullOrEmpty(series.Fanart))
                {
                    series.Fanart = xseries.Element("fanart") != null ? xseries.Element("fanart").Value : "";
                    downloadFanart = true;
                }
                if (string.IsNullOrEmpty(series.Poster))
                {
                    series.Poster = xseries.Element("poster") != null ? xseries.Element("poster").Value : "";
                    downloadPoster = true;
                }
                series.Zap2ItId = xseries.Element("zap2it_id") != null ? xseries.Element("zap2it_id").Value : "";

                if (xseries.Element("ContentRating") != null)
                {
                    temp = xseries.Element("ContentRating").Value;
                    TVContentRating contentRating = ctx.TVContentRatings.SingleOrDefault(r => r.Description == temp);
                    if (contentRating == null)
                    {
                        contentRating = new TVContentRating() { Description = temp };
                        ctx.TVContentRatings.InsertOnSubmit(contentRating);
                    }
                    contentRating.Series.Add(series);
                }

                // clear out the genres before proceeding, just in case they already exist, so we don't get duplicates
                ctx.Series_Genres.DeleteAllOnSubmit(ctx.Series_Genres.Where(g => g.SeriesId == seriesId));
                if (xseries.Element("Genre") != null)
                {
                    temp = xseries.Element("Genre").Value;
                    var split = temp.Split('|').Where(s => !string.IsNullOrEmpty(s));
                    foreach (string temp2 in split)
                    {
                        Genre genre = ctx.Genres.SingleOrDefault(r => r.GenreDesc == temp2);
                        if (genre == null)
                        {
                            genre = new Genre() { GenreDesc = temp2 };
                            ctx.Genres.InsertOnSubmit(genre);
                        }

                        Series_Genre seriesGenre = new Series_Genre();
                        series.Series_Genres.Add(seriesGenre);
                        genre.Series_Genres.Add(seriesGenre);
                    }
                }

                if (xseries.Element("Language") != null)
                {
                    temp = xseries.Element("Language").Value;
                    Language language = ctx.Languages.SingleOrDefault(l => l.Abbreviation == temp);
                    if (language != null)
                        language.Series.Add(series);
                }

                if (xseries.Element("Network") != null)
                {
                    temp = xseries.Element("Network").Value;
                    Network network = ctx.Networks.SingleOrDefault(r => r.Name == temp);
                    if (network == null)
                    {
                        network = new Network() { Name = temp };
                        ctx.Networks.InsertOnSubmit(network);
                    }
                    network.Series.Add(series);
                }

                if (xseries.Element("Status") != null)
                {
                    temp = xseries.Element("Status").Value;
                    TVStatus status = ctx.TVStatus.SingleOrDefault(r => r.Description == temp);
                    if (status == null)
                    {
                        status = new TVStatus() { Description = temp };
                        ctx.TVStatus.InsertOnSubmit(status);
                    }
                    status.Series.Add(series);
                }

                ctx.SubmitChanges();
                // download images

                DirectoryInfo dir = new DirectoryInfo(folderLocation);
                if (!dir.Exists)
                    dir.Create();

                WebClient client = new WebClient();
                if (!string.IsNullOrEmpty(series.Banner) && downloadBanner)
                {
                    try
                    {
                        if (DataUpdated != null)
                            DataUpdated("Downloading Banner Image");
                        client.DownloadFile(GraphicsUrl + series.Banner, Path.Combine(dir.FullName, "banner.jpg"));
                    }
                    catch { }
                }
                if (!string.IsNullOrEmpty(series.Fanart) && downloadFanart)
                {
                    try
                    {
                        if (DataUpdated != null)
                            DataUpdated("Downloading Fan Art Image");
                        client.DownloadFile(GraphicsUrl + series.Fanart, Path.Combine(dir.FullName, "fanart.jpg"));
                    }
                    catch { }
                }
                if (!string.IsNullOrEmpty(series.Poster) && downloadPoster)
                {
                    try
                    {
                        if (DataUpdated != null)
                            DataUpdated("Downloading Poster Image");
                        client.DownloadFile(GraphicsUrl + series.Poster, Path.Combine(dir.FullName, "folder.jpg"));
                    }
                    catch { }
                }

            }
            catch { }
        }

        private void ParseEpisodesXml(ref Series series, ref MyMoviesBrowserDataContext ctx, string xml)
        {
            XDocument doc = XDocument.Parse(xml);

            foreach (XElement xepisode in doc.Descendants("Episode"))
            {
                try
                {

                    int episodeId = int.Parse(xepisode.Element("id").Value);

                    Episode episode = ctx.Episodes.SingleOrDefault(s => s.EpisodeId == episodeId);
                    if (episode == null)
                    {
                        episode = new Episode() { EpisodeId = episodeId };
                        episode.DateAdded = DateTime.Now;
                    }
                    series.Episodes.Add(episode);

                    string temp = "";
                    DateTime tempDate;
                    decimal tempDecimal;
                    int tempInt;

                    episode.EpisodeName = xepisode.Element("EpisodeName") != null ? xepisode.Element("EpisodeName").Value : "";

                    if (DataUpdated != null)
                        DataUpdated("Parsing Episode: " + episode.EpisodeName);

                    if (xepisode.Element("EpisodeNumber") != null)
                    {
                        if (int.TryParse(xepisode.Element("EpisodeNumber").Value, out tempInt))
                            episode.EpisodeNumber = tempInt;
                        else
                            episode.EpisodeNumber = null;
                    }

                    if (xepisode.Element("SeasonNumber") != null)
                    {
                        if (int.TryParse(xepisode.Element("SeasonNumber").Value, out tempInt))
                            episode.SeasonNumber = tempInt;
                        else
                            episode.SeasonNumber = null;
                    }

                    if (xepisode.Element("seasonid") != null)
                    {
                        if (int.TryParse(xepisode.Element("seasonid").Value, out tempInt))
                        {
                            Season season = ctx.Seasons.SingleOrDefault(s => s.SeasonId == tempInt);
                            if (season == null)
                            {
                                season = new Season() { SeasonId = tempInt };
                                ctx.Seasons.InsertOnSubmit(season);
                            }
                            if (episode.SeasonNumber.HasValue)
                                season.SeasonNumber = episode.SeasonNumber.Value;
                            season.Episodes.Add(episode);
                            series.Seasons.Add(season);
                        }
                    }

                    if (xepisode.Element("FirstAired") != null)
                    {
                        if (DateTime.TryParse(xepisode.Element("FirstAired").Value, out tempDate))
                            episode.FirstAired = tempDate;
                        else
                            episode.FirstAired = null;
                    }

                    ctx.Episode_Persons.DeleteAllOnSubmit(ctx.Episode_Persons.Where(g => g.EpisodeId == episodeId));
                    if (xepisode.Element("GuestStars") != null)
                    {
                        temp = xepisode.Element("GuestStars").Value;
                        List<string> split = new List<string>();
                        if(temp.Contains('|'))
                            split.AddRange(temp.Split('|').Where(s => !string.IsNullOrEmpty(s)));
                        else
                            split.AddRange(temp.Split(',').Where(s => !string.IsNullOrEmpty(s)));
                        foreach (string temp2 in split.Distinct())
                        {
                            Person person = ctx.Persons.SingleOrDefault(r => r.PersonName == temp2.Trim());
                            if (person == null)
                            {
                                person = new Person() { PersonName = temp2.Trim() };
                                ctx.Persons.InsertOnSubmit(person);
                            }

                            Episode_Person episodePerson = new Episode_Person();
                            episode.Episode_Persons.Add(episodePerson);
                            person.Episode_Persons.Add(episodePerson);
                        }
                    }

                    episode.IMDB_ID = xepisode.Element("IMDB_ID") != null ? xepisode.Element("IMDB_ID").Value : "";

                    if (xepisode.Element("Language") != null)
                    {
                        temp = xepisode.Element("Language").Value;
                        Language language = ctx.Languages.SingleOrDefault(l => l.Abbreviation == temp);
                        if (language != null)
                            language.Episodes.Add(episode);
                    }

                    episode.Overview = xepisode.Element("Overview") != null ? xepisode.Element("Overview").Value : "";

                    if (xepisode.Element("Rating") != null)
                    {
                        if (decimal.TryParse(xepisode.Element("Rating").Value, out tempDecimal))
                            episode.Rating = tempDecimal;
                        else
                            episode.Rating = null;
                    }

                    episode.ProductionCode = xepisode.Element("ProductionCode") != null ? xepisode.Element("ProductionCode").Value : "";
                    episode.Filename = xepisode.Element("filename") != null ? xepisode.Element("filename").Value : "";

                    ctx.SubmitChanges();
                }
                catch (Exception ex)
                {
                    string tempex = ex.Message;
                }
            }
        }

        private void ParseBannersXml(ref Series series, ref MyMoviesBrowserDataContext ctx, string xml)
        {
            int seriesId = series.SeriesId;
            //ctx.Banners.DeleteAllOnSubmit(ctx.Banners.Where(b => b.SeriesId == seriesId));
            if (DataUpdated != null)
                DataUpdated("Parsing Banner Data");

            XDocument doc = XDocument.Parse(xml);

            string temp;
            int tempInt;

            foreach (XElement xbanner in doc.Descendants("Banner"))
            {
                try
                {
                    int bannerId = int.Parse(xbanner.Element("id").Value);

                    if (DataUpdated != null)
                        DataUpdated("Importing Banner " + bannerId.ToString());

                    Banner banner = ctx.Banners.SingleOrDefault(b => b.BannerId == bannerId);
                    if (banner == null)
                    {
                        banner = new Banner() { BannerId = bannerId };
                        ctx.Banners.InsertOnSubmit(banner);
                    }
                    series.Banners.Add(banner);

                    banner.BannerPath = xbanner.Element("BannerPath") != null ? xbanner.Element("BannerPath").Value : "";
                    banner.BannerType = xbanner.Element("BannerType") != null ? xbanner.Element("BannerType").Value : "";
                    banner.BannerType2 = xbanner.Element("BannerType2") != null ? xbanner.Element("BannerType2").Value : "";
                    banner.ThumbnailPath = xbanner.Element("ThumbnailPath") != null ? xbanner.Element("ThumbnailPath").Value : "";
                    banner.VignettePath = xbanner.Element("VignettePath") != null ? xbanner.Element("VignettePath").Value : "";

                    if (xbanner.Element("Season") != null)
                    {
                        if (int.TryParse(xbanner.Element("Season").Value, out tempInt))
                            banner.Season = tempInt;
                        else
                            banner.Season = null;
                    }

                    ctx.Banner_Colors.DeleteAllOnSubmit(ctx.Banner_Colors.Where(g => g.BannerId == bannerId));
                    if (xbanner.Element("Colors") != null)
                    {
                        temp = xbanner.Element("Colors").Value;
                        var split = temp.Split('|').Where(s => !string.IsNullOrEmpty(s));
                        foreach (string temp2 in split)
                        {
                            Color color = ctx.Colors.SingleOrDefault(r => r.ColorValue == temp2);
                            if (color == null)
                            {
                                color = new Color() { ColorValue = temp2 };

                                string[] split2 = temp2.Split(',');
                                if (split2.Length == 3)
                                {
                                    if (int.TryParse(split2[0], out tempInt))
                                        color.Red = tempInt;
                                    if (int.TryParse(split2[1], out tempInt))
                                        color.Green = tempInt;
                                    if (int.TryParse(split2[2], out tempInt))
                                        color.Blue = tempInt;
                                }

                                ctx.Colors.InsertOnSubmit(color);
                            }

                            Banner_Color bannerColor = new Banner_Color();
                            color.Banner_Colors.Add(bannerColor);
                            banner.Banner_Colors.Add(bannerColor);
                        }
                    }

                    if (xbanner.Element("Language") != null)
                    {
                        temp = xbanner.Element("Language").Value;
                        Language language = ctx.Languages.SingleOrDefault(l => l.Abbreviation == temp);
                        if (language != null)
                            language.Banners.Add(banner);
                    }

                    ctx.SubmitChanges();
                }
                catch (Exception ex)
                {
                    string message = ex.Message;
                }
            }
        }

        private void ParseActorsXml(ref Series series, ref MyMoviesBrowserDataContext ctx, string xml)
        {
            if (DataUpdated != null)
                DataUpdated("Parsing Actor Data");

            int seriesId = series.SeriesId;
            ctx.Series_Persons.DeleteAllOnSubmit(ctx.Series_Persons.Where(b => b.SeriesId == seriesId));

            XDocument doc = XDocument.Parse(xml);

            string temp;
            int tempInt;
            WebClient client = new WebClient();

            foreach (XElement xActor in doc.Descendants("Actor"))
            {
                try
                {
                    int actorId = int.Parse(xActor.Element("id").Value);
                    Series_Person actor = ctx.Series_Persons.SingleOrDefault(b => b.SeriesPersonId == actorId);
                    if (actor == null)
                    {
                        actor = new Series_Person() { SeriesPersonId = actorId };
                        ctx.Series_Persons.InsertOnSubmit(actor);
                    }

                    temp = xActor.Element("Name").Value;

                    if (DataUpdated != null)
                        DataUpdated("Importing Actor: " + temp);

                    Person person = ctx.Persons.SingleOrDefault(p => p.PersonName == temp);
                    if (person == null)
                    {
                        person = new Person() { PersonName = temp };
                        ctx.Persons.InsertOnSubmit(person);
                    }

                    actor.Image = xActor.Element("Image") != null ? xActor.Element("Image").Value : "";
                    actor.Role = xActor.Element("Role") != null ? xActor.Element("Role").Value : "";

                    if (xActor.Element("SortOrder") != null)
                    {
                        if (int.TryParse(xActor.Element("SortOrder").Value, out tempInt))
                            actor.SortOrder = tempInt;
                        else
                            actor.SortOrder = null;
                    }

                    person.Series_Persons.Add(actor);
                    series.Series_Persons.Add(actor);



                    if (!string.IsNullOrEmpty(actor.Image))
                    {

                        DirectoryInfo actorsDir = new DirectoryInfo(Path.Combine(series.FolderLocation, "actors"));
                        if (!actorsDir.Exists)
                            actorsDir.Create();

                        try
                        {
                            tempInt = actor.Image.LastIndexOf("/");
                            temp = actor.Image.Substring(tempInt + 1);
                            string imageUrl = GraphicsUrl + actor.Image;
                            string imageLocation = Path.Combine(actorsDir.FullName, temp);
                            if (!File.Exists(imageLocation))
                            {
                                if (DataUpdated != null)
                                    DataUpdated("Downloading Actor Image");
                                client.DownloadFile(GraphicsUrl + actor.Image, imageLocation);
                            }
                            actor.ImageLocation = imageLocation;
                        }
                        catch { }
                    }

                    ctx.SubmitChanges();

                }
                catch (Exception ex)
                {
                    string errormessage = ex.Message;
                }
            }
        }

        private delegate List<Episode> UpdateEpisodeFilesDelegate(int seriesId);
        public List<Episode> UpdateEpisodeFiles(int seriesId)
        {
            MyMoviesBrowserDataContext ctx = GetContext();
            DataLoadOptions options = new DataLoadOptions();
            options.LoadWith<Series>(s => s.Episodes);
            ctx.LoadOptions = options;

            List<Episode> episodes = new List<Episode>();

            Series series = ctx.Series.SingleOrDefault(s => s.SeriesId == seriesId);
            if (series == null)
                return episodes;
            DirectoryInfo dir = new DirectoryInfo(series.FolderLocation);
            if (!dir.Exists)
                return episodes;

            foreach (DirectoryInfo season in dir.GetDirectories("Season*"))
            {
                episodes.AddRange(AddFilesToSeries(season.GetFiles().Select(f => f.FullName), series.SeriesId, null));
            }

            return episodes;
        }
        public void UpdateEpisodeFilesAsync(int seriesId)
        {
            UpdateEpisodeFilesDelegate worker = new UpdateEpisodeFilesDelegate(UpdateEpisodeFiles);
            AsyncCallback completedCallback = new AsyncCallback(UpdateEpisodeFilesCallback);

            AsyncOperation async = AsyncOperationManager.CreateOperation(null);
            worker.BeginInvoke(seriesId, completedCallback, async);
        }
        private void UpdateEpisodeFilesCallback(IAsyncResult ar)
        {
            // get the original worker delegate and the AsyncOperation instance
            UpdateEpisodeFilesDelegate worker =
              (UpdateEpisodeFilesDelegate)((AsyncResult)ar).AsyncDelegate;
            AsyncOperation async = (AsyncOperation)ar.AsyncState;

            // finish the asynchronous operation
            List<Episode> episodes = worker.EndInvoke(ar);

            // raise the completed event
            //AsyncCompletedEventArgs completedArgs = new AsyncCompletedEventArgs(null, false, episdoe);
            async.PostOperationCompleted(
              delegate(object e)
              { OnUpdateEpisodeFilesCompleted((List<Episode>)e); },
              episodes);
        }
        public event UpdateEpisodeFilesEvent UpdateEpisodeFilesCompleted;
        protected virtual void OnUpdateEpisodeFilesCompleted(List<Episode> e)
        {
            if (UpdateEpisodeFilesCompleted != null)
                UpdateEpisodeFilesCompleted(e);
        }



        private delegate List<Episode> AddFilesToSeriesDelegate2(IEnumerable<string> filePaths, int seriesId, int? tSeason);
        public List<Episode> AddFilesToSeries(IEnumerable<string> filePaths, int seriesId, int? tSeason)
        {
            string[] regEx = new string[] { "s(\\d+)e(\\d+)", @"\b(\d+)" };
            MyMoviesBrowserDataContext ctx = GetContext();
            List<Episode> episodes = new List<Episode>();

            foreach (string filePath in filePaths)
            {
                //if (ctx.Episodes.Where(e => e.SeriesId == seriesId && e.FileLocation == filePath).Count() > 0)
                //    continue;


                try
                {
                    FileInfo file = new FileInfo(filePath);

                    int seasonNum = -1, episodeNum = -1;
                    Regex regex = new Regex(regEx[0], RegexOptions.IgnoreCase);
                    if (regex.IsMatch(file.Name))
                    {
                        Match match = regex.Match(file.Name);
                        seasonNum = int.Parse(match.Groups[1].Value);
                        episodeNum = int.Parse(match.Groups[2].Value);
                    }
                    else
                    {
                        regex = new Regex(regEx[1], RegexOptions.IgnoreCase);
                        if (regex.IsMatch(file.Name))
                        {
                            Match match = regex.Match(file.Name);
                            episodeNum = int.Parse(match.Groups[1].Value);

                            regex = new Regex("season (\\d+)", RegexOptions.IgnoreCase);
                            if (regex.IsMatch(file.Directory.Name))
                            {
                                Match match2 = regex.Match(file.Directory.Name);
                                seasonNum = int.Parse(match2.Groups[1].Value);
                            }
                            else if (tSeason.HasValue)
                                seasonNum = tSeason.Value;
                        }
                    }
                    if (episodeNum > -1 && seasonNum > -1)
                    {

                        int episodeId = ctx.Episodes.SingleOrDefault(e => e.SeriesId == seriesId && e.EpisodeNumber == episodeNum && e.SeasonNumber == seasonNum).EpisodeId;
                        episodes.Add(AddFileToSeries(episodeId, filePath));
                    }

                }
                catch (Exception ex)
                {
                    string message = ex.Message;
                    if (DataUpdated != null)
                        DataUpdated("Could not import file");
                }                
            }
            return episodes;

        }
        public void AddFilesToSeriesAsync(IEnumerable<string> filePaths, int seriesId, int? tSeason)
        {
            AddFilesToSeriesDelegate2 worker = new AddFilesToSeriesDelegate2(AddFilesToSeries);
            AsyncCallback completedCallback = new AsyncCallback(AddFilesToSeriesCallback2);

            AsyncOperation async = AsyncOperationManager.CreateOperation(null);
            worker.BeginInvoke(filePaths,seriesId,tSeason, completedCallback, async);
        }
        private void AddFilesToSeriesCallback2(IAsyncResult ar)
        {
            // get the original worker delegate and the AsyncOperation instance
            AddFilesToSeriesDelegate2 worker =
              (AddFilesToSeriesDelegate2)((AsyncResult)ar).AsyncDelegate;
            AsyncOperation async = (AsyncOperation)ar.AsyncState;

            // finish the asynchronous operation
            List<Episode> episodes = worker.EndInvoke(ar);

            // raise the completed event
            //AsyncCompletedEventArgs completedArgs = new AsyncCompletedEventArgs(null, false, episdoe);
            async.PostOperationCompleted(
              delegate(object e)
              { OnAddFilesToSeriesCompleted((List<Episode>)e); },
              episodes);
        }
        public event AddFilesToSeriesEvent AddFilesToSeriesCompleted;
        protected virtual void OnAddFilesToSeriesCompleted(List<Episode> e)
        {
            if (AddFilesToSeriesCompleted != null)
                AddFilesToSeriesCompleted(e);
        }

        private delegate Episode AddFileToSeriesDelegate(int episodeId, string filePath);
        public Episode AddFileToSeries(int episodeId, string filePath)
        {
            string message = "";
            if (DataUpdated != null)
                DataUpdated("Importing File: " + filePath);
            string[] regEx = new string[] { "s(\\d+)e(\\d+)", @"\b(\d+)" };
            MyMoviesBrowserDataContext ctx = GetContext();
            bool moveFile = Settings.Default.MoveFile;
            try
            {
                Episode episode = ctx.Episodes.SingleOrDefault(e => e.EpisodeId == episodeId);
                if (episode != null)
                {
                    FileInfo file = new FileInfo(filePath);
                    if (DataUpdated != null)
                        DataUpdated("Adding file to episode: " + episode.EpisodeName);
                    string targetFile = file.Name;
                    if (Settings.Default.RenameFile)
                    {
                        moveFile = true;
                        targetFile = string.Format(Settings.Default.RenameFormat + "{4}", episode.Series.SeriesName, episode.SeasonNumber, episode.EpisodeName, episode.EpisodeNumber, file.Extension);
                    }
                    targetFile = Regex.Replace(targetFile, @"[?:\/*""<>|]", "");
                    targetFile = Path.Combine(Path.Combine(episode.Series.FolderLocation, "Season " + episode.SeasonNumber.Value.ToString()), targetFile);

                    DirectoryInfo targetDirectory = new DirectoryInfo(Path.GetDirectoryName(targetFile));
                    if (!targetDirectory.Exists)
                        targetDirectory.Create();

                    WebClient client = new WebClient();
                    string folderPoster = Path.Combine(targetDirectory.FullName, "folder.jpg");
                    if (!File.Exists(folderPoster))
                    {

                        Banner banner = ctx.Banners.FirstOrDefault(b => b.SeriesId == episode.SeriesId && b.Season.HasValue && b.Season.Value == episode.SeasonNumber.Value && b.LanguageId == episode.LanguageId);
                        if (banner != null)
                        {
                            if (DataUpdated != null)
                                DataUpdated("Dowloading Folder Poster");

                            client.DownloadFile(Path.Combine(GraphicsUrl, banner.BannerPath), folderPoster);
                        }
                    }

                    DirectoryInfo metaDataFolder = new DirectoryInfo(Path.Combine(targetDirectory.FullName, "metadata"));
                    if (!metaDataFolder.Exists)
                        metaDataFolder.Create();

                    string episodeImage = Path.Combine(metaDataFolder.FullName, Path.GetFileNameWithoutExtension(targetFile) + ".jpg");
                    if (!File.Exists(episodeImage) && !string.IsNullOrEmpty(episode.Filename))
                    {
                        if (DataUpdated != null)
                            DataUpdated("Dowloading Episode Poster: " + episode.EpisodeNameAndNumber);

                        try
                        {
                            client.DownloadFile(Path.Combine(GraphicsUrl, episode.Filename), episodeImage);
                            episode.ImageFileLocation = episodeImage;
                        }
                        catch { }
                    }

                    if (file.FullName != targetFile)
                    {
                        if (moveFile)
                        {
                            if (DataUpdated != null)
                                DataUpdated("Moving File for Episode: " + episode.EpisodeNameAndNumber);
                            file.MoveTo(targetFile);
                        }
                        else
                        {
                            if (DataUpdated != null)
                                DataUpdated("Copying File for Episode: " + episode.EpisodeNameAndNumber);
                            file.CopyTo(targetFile, true);
                        }
                    }
                    episode.FileLocation = targetFile;
                    ctx.SubmitChanges();

                    return episode;
                }
            }
            catch (Exception ex)
            {
                message = ex.Message;
            }
            if (DataUpdated != null)
                DataUpdated("Could not import file: " + message);
            return null;
        }
        public void AddFileToSeriesAsync(int episodeId, string filePath)
        {
            AddFileToSeriesDelegate worker = new AddFileToSeriesDelegate(AddFileToSeries);
            AsyncCallback completedCallback = new AsyncCallback(AddFileToSeriesCallback);
            
            AsyncOperation async = AsyncOperationManager.CreateOperation(null);
            worker.BeginInvoke(episodeId, filePath, completedCallback, async);            
        }
        private void AddFileToSeriesCallback(IAsyncResult ar)
        {
            // get the original worker delegate and the AsyncOperation instance
            AddFileToSeriesDelegate worker =
              (AddFileToSeriesDelegate)((AsyncResult)ar).AsyncDelegate;
            AsyncOperation async = (AsyncOperation)ar.AsyncState;

            // finish the asynchronous operation
            Episode episdoe = worker.EndInvoke(ar);

            // raise the completed event
            //AsyncCompletedEventArgs completedArgs = new AsyncCompletedEventArgs(null, false, episdoe);
            async.PostOperationCompleted(
              delegate(object e)
              { OnAddFileToSeriesCompleted((Episode)e); },
              episdoe);
        }
        public event AddFileToSeriesEvent AddFileToSeriesCompleted;
        protected virtual void OnAddFileToSeriesCompleted(Episode e)
        {
            if (AddFileToSeriesCompleted != null)
                AddFileToSeriesCompleted(e);
        }

        public void WatchSeason(Season season)
        {
            MyMoviesBrowserDataContext ctx = GetContext();
            Season season2 = ctx.Seasons.SingleOrDefault(s => s.SeasonId == season.SeasonId);
            season2.WatchSeason = season.WatchSeason;
            ctx.SubmitChanges();
        }

        public void SetEpisodeWatchedStatus(Episode episode)
        {
            MyMoviesBrowserDataContext ctx = GetContext();
            Episode ep2 = ctx.Episodes.SingleOrDefault(s => s.EpisodeId == episode.EpisodeId);
            ep2.Watched = episode.Watched;
            ctx.SubmitChanges();
        }

        public List<Season> GetWatchedSeasons()
        {
            MyMoviesBrowserDataContext ctx = GetContext();
            DataLoadOptions options = new DataLoadOptions();
            options.LoadWith<Season>(s => s.Series);
            options.LoadWith<Season>(s => s.Episodes);
            options.LoadWith<Episode>(s => s.Series);
            ctx.LoadOptions = options;

            var q = (from s in ctx.Seasons
                    where s.WatchSeason
                    orderby s.Series.SeriesName, s.SeasonNumber
                    select s).ToList();
            foreach(Season season in q)
            {
                var episodes = season.Episodes.Where(e => !string.IsNullOrEmpty(e.FileLocation) || (e.FirstAired.HasValue && e.FirstAired.Value.Date > DateTime.Now.Date)).ToList();
                foreach (Episode episode in episodes)
                    season.Episodes.Remove(episode);                
            }

            return q.ToList();
        }
    }

    
}
